Управляемая куча может быть представлена лентой битов. Такая куча есть у каждого процесса своя. Для 32 разрядных максимальный размер до 1.5гб, а для 64разрядных 8 тб.
В CLR оператор new:
Такой способ имеет недостаток в виде циклических зависимостей которые нужно выявлять.
Отслеживание ссылок
Примечание, статическое поле хранит объект бессрочно, поэтому утечки памяти могут возникать, если такое поле хранит ссылку на коллекцию не нужных объектов.
Чтобы точно указать, когда пора убивать объект нужно вызывать .Dispose().
Такой метод может и продлить жизнь, так, если использовать переменную таймер, которая будет раз во сколько то раз что то делать, то есть вероятность что она умрет до завершения метода где была определена.
Алгоритм поколений строиться на следующих предположениях:
Алгоритм:
CLR умеет сам анализировать код и выбирать оптимальные границы.
Если памяти не хватает, то перед OutOfMemoryException происходит полная сборка мусора.
Класс GCNotification выдает событие при собрки мусора в поколении 0 или 2.
В .Net большими объектами считаются объекты больше 8500 байт.
Такие объекты хранятся в отдельном месте Large Object Heap
В отличии от обычной кучи, в ней не происходит сжатия, так как перекопировать очень трудозатратно. Эта отдельная зона памяти считается поколением 2 и чиститься только вместе со всем остальным поколением 2. По этой причине большие объекты следует создавать долгоживущими.
ASP.NET Core по умолчанию использует серверную сборку мусора.
Серверную сборку мусора можно включить через конфигурационный файл CLR.
Также существуют подрежимы сборщика мусора.
Запретить параллельную сборку мусора также можно через конфиг CLR.
И такой сборки есть два режима, форсед который собирает везде и оптимайзед который собирает только там где надо и где есть смысл.
Сборка происходит через System.GC
Почти во всех случаях лезть в сборщик не нужно. Но есть уникальные случаи когда все таки надо
Метод финализации пишется как конструктор с припиской ~SomeClass()
Финализация нужна для освобождения ресурсов системы, это могут быть дескрипторы или потоки.
(В первых версиях шарпа финализаторы назывались дескрипторами, но потом отказались, т.к. не похоже и путает)
Метод финализации запускается, если он был переопределен. (Есть виртуальный метод в классе обжект) Также, в IL метод пишется как Finalize()
Метод финализации запускается перед сборкой этого объекта из кучи.
Алгоритм:
Нюансы:
- Если блокнуть поток в финализации, то будет утечка памяти для всех объектов с финализацией в будущем.
- Перевод в другое поколение - оч плохо, поэтому финализацию лучше не применять.
- В финализации можно использовать другие ссылочне переменные, с этим проблем нет.
- Запуск финализаторов выполняется однопоточно
Из-за описаных проблем рекомендуется использовать интерфейс IDispose;
Паттерн заключается в реализации интерфейса IDispose, который имеет один метод Dispose.
Также требуется использовать конструкции using, которые разворачиваются в try finally, который запускает реализованный Dispose.
Также, можно реализовывать и IDispose и финализатор, на случай если по какой то причине finally не сработал.
Using можно вкладывать друг в друга.